/*
 * ©2009-2018 南京擎盾信息科技有限公司 All rights reserved.
 */
package com.wuhao.code.check.inspection.inspections

import com.aegis.mybatis.xmlless.constant.Annotations
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.XmlElementFactory
import com.intellij.psi.XmlElementVisitor
import com.intellij.psi.util.parentOfType
import com.intellij.psi.xml.XmlTag
import com.intellij.psi.xml.XmlText
import com.intellij.psi.xml.XmlToken
import com.wuhao.code.check.completion.isAfterFromOrJoin
import com.wuhao.code.check.constants.InspectionNames.MYBATIS_XML_CHECK
import com.wuhao.code.check.getStringAnnoValue
import com.wuhao.code.check.gotohandler.*
import org.jetbrains.kotlin.psi.psiUtil.parents

/**
 * @author 吴昊
 * @since 1.0
 */
class MybatisXmlInspection : BaseInspection(MYBATIS_XML_CHECK) {

  override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
    return object : XmlElementVisitor() {

      override fun visitXmlTag(tag: XmlTag) {
        val classId = getNamespace(tag) ?: return
        JavaPsiFacade.getInstance(tag.project).findClass(classId, tag.resolveScope) ?: return
        if (tag.getAttributeValue("id") != null || tag.parents.any {
              it is XmlTag && it.getAttributeValue("id") != null
            }) {
          super.visitXmlTag(tag)
        }
      }

      override fun visitXmlToken(token: XmlToken) {
        if (isAfterFromOrJoin(token)) {
          val clazz = resolveEntityClass(token)
          if (clazz.size != 1) {
            holder.registerProblem(
                token, if (clazz.isEmpty()) "找不到${token.text}对应的实体类" else "找到多个名为${token.text}的实体类",
                ProblemHighlightType.ERROR
            )
          }
          return
        }

        if (!token.text.contains(".") || token.parentOfType<XmlText>() == null) {
          return
        }
        if (!isConvertEntityMethod(token)) {
          return
        }
        val res = resolveProperty(token, 0) ?: return
        if (res.clazz != null && res.field == null) {
          holder.registerProblem(
              token, "找不到对应的属性",
              ProblemHighlightType.WARNING, Fixer(res)
          )
        }
      }

    }
  }

}


/**
 * @author 吴昊
 * @date 2024/02/01
 * @version 1.0
 * @since v1.0.0
 */
private class Fixer(private val res: Result) : LocalQuickFix {

  override fun getFamilyName(): String {
    return "转换为持久化对象属性"
  }

  override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
    val token = descriptor.psiElement
    if (res.clazz == null) {
      return
    }
    res.clazz.allFields.forEach { field ->
      if (field.hasAnnotation(Annotations.Jakarta.COLUMN)) {
        val columnName = field.getStringAnnoValue(Annotations.Jakarta.COLUMN, "name")
          ?: field.getStringAnnoValue(Annotations.Javax.COLUMN, "name")
          ?: field.getStringAnnoValue(Annotations.Plus.TABLE_FIELD, "value")
        if (res.fieldName.lowercase() == columnName?.lowercase()) {
          val newToken = XmlElementFactory.getInstance(project)
              .createDisplayText(token.text.replace(res.text, res.alias + "." + field.name))
              .firstChild
          if (newToken is XmlToken) {
            token.replace(newToken)
          }
        }
      }
    }
  }

}
